package com.hashnode.proj0001firstspringsecurity.authentication.filters;

import com.google.common.collect.Maps;
import com.hashnode.proj0001firstspringsecurity.authentication.OtpAuthentication;
import com.hashnode.proj0001firstspringsecurity.authentication.UsernamePasswordAuthentication;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.crypto.SecretKey;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Component
public class InitialAuthenticationFilter extends OncePerRequestFilter {

    //自动注入AuthenticationManager，由它应用正确的认证逻辑
    @Autowired
    private AuthenticationManager manager;

    //从配置文件中获取用于签署JWT令牌的密钥值。
    @Value("${jwt.signing.key}")
    private String signingKey;

    //重写doFilterInternal()，根据请求进行正确的认证。
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String username = request.getHeader("username");
        String password = request.getHeader("password");
        String code = request.getHeader("code");

        if (code == null) {
            Authentication a = new UsernamePasswordAuthentication(username, password);
            manager.authenticate(a);
        }
        //为OTP代码不为空的情况添加分支。在这种情况下，我们认为客户端为第二个认证步骤发送了一个OTP。
        else {
            //对于第二个认证步骤，创建一个OtpAuthentication类型的实例，并将其发送给AuthenticationManager，后者为其找到一个合适的提供者。
            Authentication a = new OtpAuthentication(username, code);
            manager.authenticate(a);

            HashMap<String, String> claimMap = new HashMap<>();
            claimMap.put("username", username);

            SecretKey key = Keys.hmacShaKeyFor(signingKey.getBytes(StandardCharsets.UTF_8));

            //构建一个JWT，并将认证用户的用户名作为主体之一。我们使用密钥来签署该token。
            String jwt = Jwts.builder()
                    .setClaims(claimMap)
                    .signWith(key)
                    .compact();

            //将令牌添加到HTTP响应的授权标头中。
            response.setHeader("Authorization", jwt);
        }

    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        //该过滤器只适用于/login路径。
        return !request.getServletPath().equals("/login");
    }
}
